

import redis.clients.jedis.Jedis;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;

public class EditableMapPanel extends JPanel {
    private BitSet grid;
    private int rows, cols;
    private final Set<Point> obstacles = new HashSet<>();
    private Point hoverPoint = new Point(-1, -1);

    public EditableMapPanel(int rows, int cols) {
        initGrid(rows, cols);
        initInteraction();
    }

    private void initGrid(int rows, int cols) {
        this.rows = rows;
        this.cols = cols;
        this.grid = new BitSet(rows * cols);
        updateRedis();
    }

    private void initInteraction() {
        addMouseMotionListener(new MouseAdapter() {
            public void mouseMoved(MouseEvent e) {
                updateHover(e.getX(), e.getY());
            }
        });

        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if (SwingUtilities.isLeftMouseButton(e)) {
                    handleClick(e.getX(), e.getY());
                }
            }
        });
    }

    private void handleClick(int x, int y) {
        Point p = convertToGrid(x, y);
        if (isValid(p)) {
            toggleCell(p);
            updateRedis();
            repaint();
        }
    }

    private void toggleCell(Point p) {
        int index = p.y * cols + p.x;
        boolean newState = !grid.get(index);
        grid.set(index, newState);

        if (newState) {
            obstacles.add(new Point(p.x, p.y));
        } else {
            obstacles.remove(new Point(p.x, p.y));
        }
    }

    private void updateHover(int x, int y) {
        Point p = convertToGrid(x, y);
        if (!p.equals(hoverPoint)) {
            hoverPoint = p;
            repaint();
        }
    }

    private Point convertToGrid(int x, int y) {
        int cellSize = getCellSize();
        return new Point(x / cellSize, y / cellSize);
    }

    private boolean isValid(Point p) {
        return p.x >= 0 && p.x < cols && p.y >= 0 && p.y < rows;
    }

    public void updateGrid(int newRows, int newCols) {
        Set<Point> preserved = new HashSet<>();
        for (Point p : obstacles) {
            if (p.x < newCols && p.y < newRows) {
                preserved.add(p);
            }
        }

        this.rows = newRows;
        this.cols = newCols;
        this.grid = new BitSet(newRows * newCols);
        preserved.forEach(p -> grid.set(p.y * cols + p.x));
        obstacles.clear();
        obstacles.addAll(preserved);

        revalidate();
        repaint();
        updateRedis();
    }

    // 随机生成障碍物
    public void randomizeObstacles(int count) {
        // 清除现有障碍物
        clearObstacles();

        List<Point> positions = new ArrayList<>();

        // 收集所有网格位置
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                positions.add(new Point(x, y));
            }
        }

        // 随机打乱位置
        Collections.shuffle(positions);

        // 设置前count个位置为障碍物
        for (int i = 0; i < Math.min(count, positions.size()); i++) {
            Point p = positions.get(i);
            setObstacle(p.x, p.y, true);
        }

        updateRedis();
        repaint();

        // 显示生成结果
        JOptionPane.showMessageDialog(this, "已生成 " + count + " 个随机障碍物");
    }

    // 清除所有障碍物
    private void clearObstacles() {
        grid.clear();
        obstacles.clear();
    }

    // 设置特定位置的障碍物状态
    private void setObstacle(int x, int y, boolean isObstacle) {
        int index = y * cols + x;
        grid.set(index, isObstacle);

        if (isObstacle) {
            obstacles.add(new Point(x, y));
        } else {
            obstacles.remove(new Point(x, y));
        }
    }

    private void updateRedis() {
        new SwingWorker<Void, Void>() {
            protected Void doInBackground() {
                try (Jedis jedis = new Jedis("localhost", 6379)) {
                    // 获取障碍物BitSet
                    BitSet bits = new BitSet(rows * cols);
                    obstacles.forEach(p -> bits.set(p.y * cols + p.x));

                    // 转换为字符串格式存储
                    String obstacleStr = RedisUtils.bitSetToString(bits, rows, cols);
                    jedis.set("map:obstacle", obstacleStr);
                } catch (Exception e) {
                    System.err.println("实时更新失败: " + e.getMessage());
                }
                return null;
            }
        }.execute();
    }

    public BitSet getObstacleBits() {
        BitSet bits = new BitSet(rows * cols);
        obstacles.forEach(p -> bits.set(p.y * cols + p.x));
        return bits;
    }

    public int getRows() { return rows; }
    public int getCols() { return cols; }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int cellSize = getCellSize();

        // 绘制网格
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                drawCell(g, x, y, cellSize);
            }
        }

        // 悬停效果
        if (hoverPoint.x >= 0 && hoverPoint.x < cols &&
                hoverPoint.y >= 0 && hoverPoint.y < rows) {
            g.setColor(new Color(255, 255, 0, 50));
            g.fillRect(hoverPoint.x * cellSize, hoverPoint.y * cellSize, cellSize, cellSize);
        }
    }

    private void drawCell(Graphics g, int x, int y, int size) {
        int index = y * cols + x;
        g.setColor(grid.get(index) ? Color.BLACK : Color.WHITE);
        g.fillRect(x * size, y * size, size, size);

        g.setColor(Color.LIGHT_GRAY);
        g.drawRect(x * size, y * size, size, size);
    }

    private int getCellSize() {
        return Math.min(getWidth() / cols, getHeight() / rows);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(500, 500);
    }
}
